home *** CD-ROM | disk | FTP | other *** search
/ Fritz: All Fritz / All Fritz.zip / All Fritz / FILES / PROGMISC / MODULA2.LZH / KERNEL.MOD < prev    next >
Text File  |  1987-10-18  |  8KB  |  303 lines

  1. IMPLEMENTATION MODULE Kernel;
  2. (* $S-, $R-, $T- *)
  3.  
  4. (* (C) Copyright 1987 Fitted Software Tools. All rights reserved.
  5.  
  6.     This module is part of the example multitasking communications program
  7.     provided with the Fitted Software Tools' Modula-2 development system.
  8.  
  9.     Registered users may use this program as is, or they may modify it to
  10.     suit their needs or as an exercise.
  11.  
  12.     If you develop interesting derivatives of this program and would like
  13.     to share it with others, we encourage you to upload a copy to our BBS.
  14. *)
  15.  
  16.  
  17. IMPORT SYSTEM, Storage;
  18. FROM SYSTEM     IMPORT ASSEMBLER, ADDRESS, NEWPROCESS;
  19. FROM System     IMPORT TermProcedure, GetVector, SetVector, ResetVector;
  20. FROM Storage    IMPORT ALLOCATE;
  21.  
  22. TYPE
  23.     Process = POINTER TO ProcessDescriptor;
  24.     ProcessDescriptor = RECORD
  25.         proc    :ADDRESS;
  26.         iop     :BOOLEAN;
  27.         next    :Process;
  28.     END;
  29.  
  30.     SignalHeader = POINTER TO SignalRec;
  31.     SignalRec = RECORD
  32.         count   :CARDINAL;
  33.         list    :Process;
  34.     END;
  35.  
  36.     LockHeader = POINTER TO LockRec;
  37.     LockRec = RECORD
  38.         count   :CARDINAL;
  39.         owner   :Process;
  40.         list    :Process;
  41.     END;
  42.  
  43. VAR
  44.     cp      :Process;           (* executing process - head of ready list *)
  45.  
  46.  
  47. PROCEDURE NewProcess( p :PROC; n :CARDINAL; iop :BOOLEAN );
  48. (*
  49.     This procedure must be run at the "no priority" level because
  50.     of the way NEWPROCESS is implemented (please refer to the
  51.     documentation, under SYSTEM).
  52. *)
  53. VAR t  :Process;
  54.     a  :ADDRESS;
  55. BEGIN
  56.     (* allocate the stack for the new process *)
  57.     ALLOCATE( a, n );
  58.     (* the new process is placed 2nd in ready list *)
  59.     NEW( t );                           (* new process *)
  60.     NEWPROCESS( p, a, n, t^.proc );     (* created *)
  61.     t^.iop := iop;
  62.     t^.next := cp^.next;                (* 2nd in list *)
  63.     cp^.next := t;
  64. END NewProcess;
  65.  
  66.  
  67. PROCEDURE InitSignal( VAR s :SignalHeader );
  68. BEGIN
  69.     NEW( s );
  70.     s^.count := 0; s^.list := NIL;
  71. END InitSignal;
  72.  
  73.  
  74. PROCEDURE InitLock( VAR l :LockHeader );
  75. BEGIN
  76.     NEW( l );
  77.     l^.count := 0; l^.list := NIL;
  78. END InitLock;
  79.  
  80.  
  81. MODULE TheKernel[0];  (* the kernel runs with all interrupts disabled *)
  82.  
  83.     IMPORT Process, SignalHeader, LockHeader, cp;
  84.     FROM SYSTEM     IMPORT ADDRESS, TRANSFER, IOTRANSFER;
  85.     FROM Storage    IMPORT ALLOCATE;
  86.  
  87.     EXPORT Signal, Wait, WaitIO, Lock, Unlock;
  88.  
  89.     PROCEDURE Signal( VAR s :SignalHeader );
  90.     VAR t, t0, t1 :Process;
  91.     BEGIN
  92.         WITH s^ DO
  93.             IF list <> NIL THEN
  94.                 (* process(es) waiting for signal *)
  95.                 (* get the first out of waiting list *)
  96.                 t := list;
  97.                 list := list^.next;
  98.  
  99.                 (* and put it into the ready list *)
  100.                 (* after cp and any iop *)
  101.                 t0 := cp;
  102.                 t1 := cp^.next;
  103.                 WHILE t1^.iop DO t0 := t1; t1 := t1^.next END;
  104.                 t^.next := t1;
  105.                 t0^.next := t;
  106.             ELSE
  107.                 INC( count );
  108.             END;
  109.         END;
  110.     END Signal;
  111.  
  112.  
  113.     PROCEDURE Wait( VAR s :SignalHeader );
  114.     VAR t0, t1 :Process;
  115.     BEGIN
  116.         WITH s^ DO
  117.             IF count = 0 THEN
  118.                 (* sorry, must wait... *)
  119.                 t0 := cp;
  120.                 cp := cp^.next;     (* grab next to activate *)
  121.                 t0^.next := NIL;    (* t0 goes to end of wait list *)
  122.                 IF list = NIL THEN
  123.                     list := t0;
  124.                 ELSE
  125.                     t1 := list;
  126.                     WHILE t1^.next <> NIL DO
  127.                         t1 := t1^.next;
  128.                     END;
  129.                     t1^.next := t0;
  130.                 END;
  131.                 TRANSFER( t0^.proc, cp^.proc );
  132.             ELSE
  133.                 (* just keep on going... *)
  134.                 DEC( count );
  135.             END;
  136.         END;
  137.     END Wait;
  138.  
  139.  
  140.     PROCEDURE Lock( VAR l :LockHeader );
  141.     VAR t0, t1 :Process;
  142.     BEGIN
  143.         WITH l^ DO
  144.             IF count = 0 THEN
  145.                 INC( count ); owner := cp;
  146.             ELSIF owner = cp THEN
  147.                 (* we do not count locks here! *)
  148.             ELSE
  149.                 (* sorry, must wait... *)
  150.                 t0 := cp;
  151.                 cp := cp^.next;     (* grab next to activate *)
  152.                 t0^.next := NIL;    (* t0 goes to end of wait list *)
  153.                 IF list = NIL THEN
  154.                     list := t0;
  155.                 ELSE
  156.                     t1 := list;
  157.                     WHILE t1^.next <> NIL DO
  158.                         t1 := t1^.next;
  159.                     END;
  160.                     t1^.next := t0;
  161.                 END;
  162.                 TRANSFER( t0^.proc, cp^.proc );
  163.             END;
  164.         END;
  165.     END Lock;
  166.  
  167.  
  168.     PROCEDURE Unlock( VAR l :LockHeader );
  169.     VAR t, t0, t1 :Process;
  170.     BEGIN
  171.         WITH l^ DO
  172.             IF (owner = cp) & (count > 0) THEN DEC( count ) END;
  173.             IF count = 0 THEN
  174.                 IF list <> NIL THEN
  175.                     (* process(es) waiting for lock *)
  176.                     (* get the first out of waiting list *)
  177.                     t := list;
  178.                     list := list^.next;
  179.  
  180.                     (* give it the lock *)
  181.                     INC( count );
  182.                     owner := t;
  183.  
  184.                     (* and put it into the ready list *)
  185.                     (* after cp and any iop *)
  186.                     t0 := cp;
  187.                     t1 := cp^.next;
  188.                     WHILE t1^.iop DO t0 := t1; t1 := t1^.next END;
  189.                     t^.next := t1;
  190.                     t0^.next := t;
  191.                 END;
  192.             END;
  193.         END;
  194.     END Unlock;
  195.  
  196.  
  197.     PROCEDURE WaitIO( v :CARDINAL );
  198.     VAR t0  :Process;
  199.         p   :ADDRESS;
  200.     BEGIN
  201.         t0 := cp;                               (* get us out of ready list *)
  202.         cp := cp^.next;
  203.         p := cp^.proc;
  204.  
  205.         IOTRANSFER( t0^.proc, p, v );    (* activate next process *)
  206.  
  207.         (* and resume here *)
  208.         cp^.proc := p;                          (* save interrupted state *)
  209.         t0^.next := cp;                         (* resume driver *)
  210.         cp := t0;
  211.     END WaitIO;
  212.  
  213. END TheKernel;
  214.  
  215.  
  216. (*PROCESS*) PROCEDURE idle;                 (* the idle process *)
  217. BEGIN
  218.     LOOP END;
  219. END idle;
  220.  
  221.  
  222. PROCEDURE IgnoreInt;
  223. BEGIN
  224.     ASM
  225.         PUSH    AX
  226.         MOV     AL, 20H
  227.         OUT     20H, AL
  228.         POP     AX
  229.         IRET
  230.     END;
  231. END IgnoreInt;
  232.  
  233. VAR OrgIntMask  :BITSET;
  234.     OrgVectors  :ARRAY [0..7] OF RECORD
  235.         saved   :BOOLEAN;
  236.         IntAdrs :ADDRESS;
  237.     END;
  238.     i           :CARDINAL;
  239.  
  240. PROCEDURE restore;
  241. BEGIN
  242.     ASM
  243.         MOV     AL, OrgIntMask
  244.         OUT     21H, AL
  245.     END;
  246.     FOR i := 0 TO 7 DO
  247.         WITH OrgVectors[i] DO
  248.             IF saved THEN
  249.                 ResetVector( 8 + i, IntAdrs );
  250.             END;
  251.         END;
  252.     END;
  253. END restore;
  254.  
  255. BEGIN
  256.     (* enable all the 8259 interrupts *)
  257.  
  258.     (* first, get the current (original) interrupt mask *)
  259.     OrgIntMask := {};
  260.     ASM
  261.         IN      AL, 21H
  262.         MOV     OrgIntMask, AL
  263.     END;
  264.  
  265.     (* save the interrupt vector values for all the disabled interrupts *)
  266.     FOR i := 0 TO 7 DO
  267.         WITH OrgVectors[i] DO
  268.             IF i IN OrgIntMask THEN
  269.                 GetVector( 8 + i, IntAdrs );
  270.                 saved := TRUE;
  271.             ELSE
  272.                 saved := FALSE
  273.             END;
  274.         END;
  275.     END;
  276.  
  277.     (* install our termination procedure *)
  278.     TermProcedure( restore );
  279.  
  280.     (* install a dummy interrupt handler for all the originally
  281.        disabled interrupts.
  282.     *)
  283.     FOR i := 0 TO 7 DO
  284.         WITH OrgVectors[i] DO
  285.             IF saved THEN
  286.                 SetVector( 8 + i, IgnoreInt );
  287.             END;
  288.         END;
  289.     END;
  290.  
  291.     (* enable all the interrupts *)
  292.     ASM
  293.         MOV     AL, 0
  294.         OUT     21H, AL
  295.     END;
  296.  
  297.  
  298.     (* start the kernel *)
  299.     NEW( cp ); cp^.next := NIL;         (* main process *)
  300.     NewProcess( idle, 400, FALSE );     (* idle process *)
  301.  
  302. END Kernel.
  303.